#include "Multitree.h"
#include <string.h>
#include <gc/gc.h>
#include <stdlib.h>
#include <ctype.h>


int good_variable_name(char * name){	//checks if the variable name is good
	while (*name != '\0'){
		if(!isalpha(*name)){
			return 0;
		}
		name++;
	}
	return 1;
}

Multitree * treevariable(char * variable){
	Multitree * tree;
	if(!good_variable_name(variable)){
		return NULL;
	}
	tree = give_me_empty_tree();
	tree->symbol.name = (char *) GC_MALLOC((strlen(variable)+1) * sizeof(char));
	if(tree->symbol.name == NULL){
		abort();
	}
	tree->symbol.type = VARIABLE;
	strcpy(tree->symbol.name, variable); //We can use strcpy, because we have enough memory (because of strlen).
	tree->childs = NULL;
	return tree;
}

Multitree * treeconstant(char * name, Multitree * number){
	Multitree * tree;
	if(!good_variable_name(name)){
		return NULL;
	}
	if(number == NULL){
		return NULL;
	}
	if(number->symbol.type != NUMBER){
		return NULL;
	}
	tree = give_me_empty_tree();
	tree->symbol.name = (char *) GC_MALLOC(sizeof(char) * strlen(name)+1);
	if(tree->symbol.name == NULL){
		abort();
	}
	tree->symbol.type = CONSTANT;
	strcpy(tree->symbol.name, name);
	tree->symbol.number = construct_number();
	numbercpy(tree->symbol.number, number->symbol.number);
	tree->childs = NULL;
	return tree;
}

Multitree * inttotree(long long int i){
	Multitree * tree;
	tree = give_me_empty_tree();
	tree->symbol.type = NUMBER;
	tree->symbol.number = construct_number();
	linttonum(tree->symbol.number, i);
	tree->childs = NULL;
	return tree;
}

Multitree * doubletotree(long double d){
	Multitree * tree;
	tree = give_me_empty_tree();
	tree->symbol.type = NUMBER;
	tree->symbol.number = construct_number();
	ldoubletonum(tree->symbol.number, d);
	tree->childs = NULL;
	return tree;
}

Multitree * treeplus(Multitree * first, Multitree * second){
	Multitree * tree;
	Multitree * tmp;
	if(first == NULL || second == NULL){
		return NULL;
	}
	tree = give_me_tree_with_two_incomplete_childs();
	tree->symbol.type = OPERATOR;
	tree->symbol.oper = PLUS;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(first);
	tree->childs->next->inverted = 0;
	tree->childs->next->subtree = copy_tree(second);
	tmp = canonicalize_tree(tree);
	if(tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}

Multitree * treeminus(Multitree * first, Multitree * second){
	Multitree * tree;
	Multitree * tmp;
	if(first == NULL || second == NULL){
		return NULL;
	}

	tree = give_me_tree_with_two_incomplete_childs();
	tree->symbol.type = OPERATOR;
	tree->symbol.oper = PLUS;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(first);
	tree->childs->next->inverted = 1;
	tree->childs->next->subtree = copy_tree(second);
	tmp = canonicalize_tree(tree);
	if(tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}

Multitree * treemul(Multitree * first, Multitree * second){
	Multitree * tree;
	Multitree * tmp;
	if(first == NULL || second == NULL){
		return NULL;
	}
	tree = give_me_tree_with_two_incomplete_childs();
	tree->symbol.type = OPERATOR;
	tree->symbol.oper = MULTIPLY;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(first);
	tree->childs->next->inverted = 0;
	tree->childs->next->subtree = copy_tree(second);
	tmp = canonicalize_tree(tree);
	if(tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}
	
Multitree * treediv(Multitree * first, Multitree * second){
	Multitree * tree;
	Multitree * tmp;
	if(first == NULL || second == NULL){
		return NULL;
	}
	tree = give_me_tree_with_two_incomplete_childs();
	tree->symbol.type = OPERATOR;
	tree->symbol.oper = MULTIPLY;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(first);
	tree->childs->next->inverted = 1;
	tree->childs->next->subtree = copy_tree(second);
	tmp = canonicalize_tree(tree);
	if(tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}

Multitree * treepow(Multitree * first, Multitree * second){
	Multitree * tree;
	Multitree * tmp;
	if(first == NULL || second == NULL){
		return NULL;
	}
	tree = give_me_tree_with_two_incomplete_childs();
	tree->symbol.type = OPERATOR;
	tree->symbol.oper = POWER;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(first);
	tree->childs->next->inverted = 0;
	tree->childs->next->subtree = copy_tree(second);
	tmp = canonicalize_tree(tree);
	if(tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}

Multitree * treesin(Multitree * argument){
	Multitree * tree;
	Multitree * tmp = NULL;
	if (argument == NULL){
		return NULL;
	}

	tree = give_me_empty_tree();
	tree->symbol.type = FUNCTION;
	tree->symbol.func = SIN;
	tree->childs = give_me_empty_child();
	tree->childs->next = NULL;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(argument);
	tmp = canonicalize_tree(tree);
	if (tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}

Multitree * treecos(Multitree * argument){
	Multitree * tree;
	Multitree * tmp = NULL;
	if (argument == NULL){
		return NULL;
	}
	tree = give_me_empty_tree();
	tree->symbol.type = FUNCTION;
	tree->symbol.func = COS;
	tree->childs = give_me_empty_child();
	tree->childs->next = NULL;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(argument);
	tmp = canonicalize_tree(tree);
	if (tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}

Multitree * treetan(Multitree * argument){
	Multitree * tree;
	Multitree * tmp = NULL;
	if (argument == NULL){
		return NULL;
	}
	tree = give_me_empty_tree();
	tree->symbol.type = FUNCTION;
	tree->symbol.func = TAN;
	tree->childs = give_me_empty_child();
	tree->childs->next = NULL;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(argument);
	tmp = canonicalize_tree(tree);
	if (tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}

Multitree * treeln(Multitree * argument){
	Multitree * tree;
	Multitree * tmp = NULL;
	if (argument == NULL){
		return NULL;
	}
	tree = give_me_empty_tree();
	tree->symbol.type = FUNCTION;
	tree->symbol.func = LN;
	tree->childs = give_me_empty_child();
	tree->childs->next = NULL;
	tree->childs->inverted = 0;
	tree->childs->subtree = copy_tree(argument);
	tmp = canonicalize_tree(tree);
	if (tmp == NULL){
		return NULL;
	}
	delete_tree(tree);
	tree = tmp;
	tmp = NULL;
	return tree;
}

Multitree * treediff(Multitree * expression, Multitree * variable){
	if (expression == NULL || variable == NULL){
		return NULL;
	}
	if (variable->symbol.type != VARIABLE){
		return NULL;
	}

	return diff_tree(expression, variable->symbol.name);
}

Multitree * tree_replace_var(Multitree * expression, Multitree * variable, Multitree * by_what){
	if (expression == NULL || by_what == NULL || variable == NULL){
		return NULL;
	}
	if (variable->symbol.type != VARIABLE){
		return NULL;
	}
	return replace_variable_tree(expression, variable->symbol.name, by_what);
}

Multitree * treeexpand(Multitree * tree){
	if (tree == NULL){
		return NULL;
	}
	else{
		return expand_tree(tree);
	}
}

Multitree * treetaylor(Multitree * tree, Multitree * center, unsigned short int terms, Multitree * variable){
	if (tree == NULL || center == NULL || variable == NULL){
		return NULL;
	}
	if(center->symbol.type !=NUMBER){
		return NULL;
	}
	if(variable->symbol.type != VARIABLE){
		return NULL;
	}
	return taylorize(tree, center, terms, variable->symbol.name);
}

